package com.fd.framework.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 系统环境监听类, 在整个项目启动时,加载必要参数到环境变量中
 * 技术点:
 * 1.springBoot启动过程中的listener机制
 * Spring Boot 在启动的不同阶段发出不同的事件。
 * 如下是 Spring Boot 启动时不同阶段事件的触发顺序。
 * starting 阶段，表示 Spring Boot 开始启动；
 * environmentPrepared 表示环境变量准备完成；
 * contextPrepared 表示上下文对象准备完成；
 * contextLoaded 表示上下文对象加载完毕；
 * started 表示 Spring Boot 启动完成；
 * running 表示此时容器运行中。如果在启动中任何阶段发生异常，进入 failed 阶段。
 *
 * @author XiaoLong
 * @since 1.0.0
 */
@Slf4j
public class ServiceEnvironmentListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
    private static final String APPLICATION_NAME_KEY = "spring.application.name";
    private static final String APPLICATION_NAME = "applicationName";
    private static final String LOG_LEVEL_KEY = "fd.log.level";
    private static final String DEFAULT_LOG_LEVEL = "INFO";
    private static final String LOG_LEVEL = "logLevel";
    private static final String LOG_CONFIG = "logging.config";
    private static final String CONFIG_LOCATION = "classpath:fd-log4j2.xml";
    private static final String PATH_MATCH_MATCHING_STRATEGY_KEY = "spring.mvc.pathmatch.matching-strategy";
    private static final String MATCHING_DEFAULT_STRATEGY = "ANT_PATH_MATCHER";
    private static final String SWAGGER_CONFIG_NAME = "swaggerConfig";


    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment environment = event.getEnvironment();
        sysNecessarySetting(environment);
    }

    /**
     * 添加运行环境必要参数
     *
     * @param environment 可配置的环境
     * @author XiaoLong
     * @since 1.0.0
     */
    private void sysNecessarySetting(ConfigurableEnvironment environment) {
        //1.自定义日志存放位置 , 固定位置 + 当前项目名+项目名.log
        addApplicationName(environment);
        addLog4j2Config(environment);
        addSwaggerConfig(environment);
    }

    /**
     * 添加服务名到系统环境变量中
     *
     * @param environment 可配置的环境
     * @author XiaoLong
     * @since 1.0.0
     */
    private void addApplicationName(ConfigurableEnvironment environment) {
        String applicationName = environment.getProperty(APPLICATION_NAME_KEY);
        Assert.notNull(applicationName, "服务名不能为空");
        System.setProperty(APPLICATION_NAME, applicationName);
    }

    /**
     * 添加log4j2参数
     * -设置log4j2配置
     * -配置log的日志级别
     *
     * @param environment 可配置的环境
     * @author XiaoLong
     * @since 1.0.0
     */
    private void addLog4j2Config(ConfigurableEnvironment environment) {
        //日志级别
        String logLevel = environment.getProperty(LOG_LEVEL_KEY);
        if (!StringUtils.hasLength(logLevel)) {
            logLevel = DEFAULT_LOG_LEVEL;
        }
        System.setProperty(LOG_LEVEL, logLevel);
        System.setProperty(LOG_CONFIG, CONFIG_LOCATION);
    }
    /**
     * 添加swagger配置文件
     *
     * @param environment 可配置环境
     * @author XiaoLong
     * @since 1.0.0
     */
    private void addSwaggerConfig(ConfigurableEnvironment environment) {
        Map<String, Object> swaggerConfigMap = new HashMap<>();
        swaggerConfigMap.put(PATH_MATCH_MATCHING_STRATEGY_KEY, MATCHING_DEFAULT_STRATEGY);
        OriginTrackedMapPropertySource swaggerSource = new OriginTrackedMapPropertySource(SWAGGER_CONFIG_NAME, swaggerConfigMap);
        environment.getPropertySources().addLast(swaggerSource);
    }


    @Override
    public int getOrder() {
        //整个服务启动时, 加载完其他的配置文件后, 再来增加一些必要的环境参数
        // +19的原因: 是在LoggingApplicationListener之前设置环境变量
        return Ordered.HIGHEST_PRECEDENCE + 19;
    }
}
